﻿Ext.Container = Ext.extend(Ext.lib.Container, {

    cardSwitchAnimation: null,

    initComponent: function () {

        // 如果组件支持滚动
        if (this.scroll) {

            // 创建表单子组件集合
            this.fields = new Ext.util.MixedCollection();

            // 如果在非黑莓手机上运行
            if (!Ext.is.Blackberry) {

                // fields注册增加、移除子组件的监听函数
                this.fields.on({
                    add: this.onFieldAdd,
                    remove: this.onFieldRemove,
                    scope: this
                });
            }

            // 组件注册增加、移除子组件的监听函数
            this.on({
                add: this.onItemAdd,
                remove: this.onItemRemove,
                scope: this
            });
        }

        // 父类initComponent方法
        Ext.Container.superclass.initComponent.apply(this, arguments);
    },

    afterRender: function () {
        Ext.Container.superclass.afterRender.apply(this, arguments);

        // 为表单组件做的滚动样式处理
        if (this.scroller) {
            if ((Ext.is.Android) && this.containsFormFields) {
                this.scroller.setUseCssTransform(false);
            }

            this.scroller.on('scrollstart', this.onFieldScrollStart, this);
        }
    },

    onFieldScrollStart: function () {
        var focusedField = this.focusedField;

        if (focusedField && Ext.is.iOS) {
            focusedField.blur();

        }
    },

    // 增加子组件触发
    onItemAdd: function (me, item) {
        // 将item的field类型子孙组件深度获取并放入fields集合中
        this.fields.addAll(Ext.ComponentQuery.query('[isField]', item));
    },

    // 移除子组件触发
    onItemRemove: function (me, item) {
        // 将item的field类型子孙组件从fields集合中移除
        this.fields.removeAll(Ext.ComponentQuery.query('[isField]', item));
    },

    // fields集合添加子组件时触发
    onFieldAdd: function (key, field) {
        this.handleFieldEventListener(true, field);
    },

    // fields集合移除子组件时触发
    onFieldRemove: function (key, field) {
        this.handleFieldEventListener(false, field);
    },

    // 给field注册添加/移除表单事件特殊处理函数
    handleFieldEventListener: function (isAdding, item) {
        if (!this.fieldEventWrap)
            this.fieldEventWrap = {};

        // 如果item是下面组件的其中之一
        if (['textfield', 'passwordfield', 'emailfield',
             'textareafield', 'searchfield', 'urlfield',
             'numberfield', 'spinnerfield'].indexOf(item.xtype) !== -1) {

            // 添加组件的情况
            if (isAdding) {

                // 表单事件结构
                this.fieldEventWrap[item.id] = {
                    beforefocus: function (e) { this.onFieldBeforeFocus(item, e); },
                    focus: function (e) { this.onFieldFocus(item, e); },
                    blur: function (e) { this.onFieldBlur(item, e); },
                    keyup: function (e) { this.onFieldKeyUp(item, e); },
                    scope: this
                };

                this.containsFormFields = true;
            }

            // 给field注册添加/移除表单事件特殊处理函数
            item[isAdding ? 'on' : 'un'](this.fieldEventWrap[item.id]);

            if (!isAdding) {
                delete this.fieldEventWrap[item.id];
            }
        }
    },

    onFieldKeyUp: function (field, e) {
        if (Ext.is.iOS || Ext.is.Desktop) {
            this.resetLastWindowScroll();
        }
    },

    onFieldBeforeFocus: function (field, e) {
        this.focusingField = field;
    },

    getLastWindowScroll: function () {
        if (!this.lastWindowScroll) {
            this.resetLastWindowScroll();
        }

        return { x: this.lastWindowScroll.x, y: this.lastWindowScroll.y };
    },

    resetLastWindowScroll: function () {
        this.lastWindowScroll = {
            x: window.pageXOffset,
            y: window.pageYOffset
        };
    },

    adjustScroller: function (offset) {
        var scroller = this.getClosestScroller(),
            windowScroll = this.getLastWindowScroll();

        scroller.setOffset(offset);


        if (Ext.is.iOS) {
            window.scrollTo(windowScroll.x, windowScroll.y);
        }

        this.resetLastWindowScroll();
    },

    onFieldFocus: function (field, e) {
        if (!Ext.is.iOS && !Ext.is.Desktop) {
            var dom = field.fieldEl.dom;

            if (dom.scrollIntoViewIfNeeded) {
                dom.scrollIntoViewIfNeeded(true); // 将不在浏览器窗口的可见区域内的元素滚动到浏览器窗口的可见区域
            }
        }
        else {
            var scroller = this.getClosestScroller(),
                containerRegion = Ext.util.Region.from(scroller.containerBox),
                fieldRegion = field.fieldEl.getPageBox(true);


            if (this.focusingField == field || !Ext.is.iOS) {
                if (Ext.is.iOS && window.pageYOffset == 0) {
                    window.scrollTo(0, 0);
                }

                var adjustment = new Ext.util.Offset();

                if (fieldRegion.left < containerRegion.left) {
                    adjustment.x = containerRegion.left - fieldRegion.left;
                }

                if (fieldRegion.top < containerRegion.top) {
                    adjustment.y = containerRegion.top - fieldRegion.top;
                }

                if (!adjustment.isZero()) {
                    var windowScroll = this.getLastWindowScroll();

                    scroller.scrollBy(adjustment);

                    if (Ext.is.iOS) {
                        window.scrollTo(windowScroll.x, windowScroll.y);
                    }

                    this.resetLastWindowScroll();
                }
            }

            else {
                if (this.lastFocusedField) {
                    var deltaY = fieldRegion.top - this.lastFocusedField.fieldEl.getY(),
                        offsetY = scroller.offset.y - deltaY,
                        selfHandling = false;

                    if (!containerRegion.contains(fieldRegion) &&
                        (offsetY != 0 || (offsetY == 0 && scroller.offset.y != 0))) {
                        selfHandling = true;
                    }

                    if (offsetY > 0) {
                        offsetY = 0;
                    }

                    if (selfHandling) {
                        this.adjustScroller(new Ext.util.Offset(
                            scroller.offset.x, offsetY
                        ));
                    }
                }
            }

            this.resetLastWindowScroll();
        }

        this.lastFocusedField = field;
        this.focusedField = field;
        this.focusingField = null;
    },

    getClosestScroller: function () {
        if (!this.closestScroller) {
            this.closestScroller = this.scroller || this.el.getScrollParent();
        }

        return this.closestScroller;
    },

    onFieldBlur: function (field, e) {
        if (this.focusingField == field) {
            this.focusingField = null;
        }

        if (this.focusedField == field) {
            this.focusedField = null;
        }
    },


    afterLayout: function (layout) {
        if (this.floating && this.centered) {
            this.setCentered(true, true);
        }

        if (this.scroller) {
            this.scroller.updateBoundary();
        }
        Ext.Container.superclass.afterLayout.call(this, layout);
    },


    getActiveItem: function () {
        if (this.layout && this.layout.type == 'card') {
            return this.layout.activeItem;
        }
        else {
            return null;
        }
    },


    setActiveItem: function (card, animation) {
        this.layout.setActiveItem(card, animation);
        return this;
    },



    onBeforeCardSwitch: function (newCard, oldCard, newIndex, animated) {
        return this.fireEvent('beforecardswitch', this, newCard, oldCard, newIndex, animated);
    },


    onCardSwitch: function (newCard, oldCard, newIndex, animated) {
        return this.fireEvent('cardswitch', this, newCard, oldCard, newIndex, animated);
    },


    disable: function () {
        Ext.Container.superclass.disable.call(this);
        this.el.mask(null, 'x-mask-gray');
    },


    enable: function () {
        Ext.Container.superclass.enable.call(this);
        this.el.unmask();
    }
});

Ext.reg('container', Ext.Container);
